/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package MouseSensorDriver;

import dynamixel.ComPortFindParam;
import dynamixel.ComPortFinder;
import dynamixel.FindSerial;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Timer;
import jssc.SerialPort;
import jssc.SerialPortEvent;
import jssc.SerialPortEventListener;
import jssc.SerialPortException;
import jssc.SerialPortList;

/**
 *
 * @author Asko
 */
public class MouseSensorHost implements Serializable{

    private static final int MOUSE_BAUD = 38400;
    private static final int[] CHECK_PACK = {};
    private static final int BYTES_CNT = 8;
    private static final int TIMEOUT = 1000;
    private ArrayList<MouseSensorListener> listeners = new ArrayList<>();
    public static SerialPort serialPort;
    private boolean toX = false;
    private int[] dx = new int[3];
    private int[] dy = new int[3];
    private int[] x = new int[3];
    private int[] y = new int[3];
    private String inputBuffer = "";
    private String partMessage = "";
    private int movePosition = 0;
    private String currentMessage = "";
    private int sumPosition = 0;
    private int charIndx = 0;
    private String value = "";
    private int elementIndx = 0;
    static String message = null;
    static String resultMessage = null;
    int chPort = -1;

    //static long x2=0,y2=0,dx2=0,dy2=0;
    public static void main(String[] args) throws InterruptedException {
        try {
            MouseSensorHost host = new MouseSensorHost("COM6", 38400);
            host.addMouseSensorListener(new MouseSensorListener() {
                @Override
                public void measured(int dx1, int dy1, int dx2, int dy2, int dx3, int dy3) {
                    System.out.println(" dx1= " + dx1 + " dy1= " + dy1 + " dx2= "
                            + dx2 + " dy2= " + dy2 + " dx3= " + dx3 + " dy3= " + dy3);
                    /*  MouseSensorHost.x2+=dx3;
                     MouseSensorHost.y2+=dy3;
                     MouseSensorHost.dx2 = dx3;
                     MouseSensorHost.dy2 = dy3;*/
                    //System.out.println("x: "+x2+"y: "+y2);
                }
            });
            Timer tmr = new Timer(100, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    //System.out.println("x: "+x2+" y: "+y2+" dx: "+dx2+" dy: "+dy2);
                }
            });
            tmr.start();
            Thread.sleep(5000);
        } catch (SerialPortException ex) {
            Logger.getLogger(MouseSensorHost.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public MouseSensorHost(int baudrate) throws SerialPortException {
        this(ComPortFinder.findCom(new ComPortFindParam(baudrate,
                SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE, BYTES_CNT,
                TIMEOUT) {
            @Override
            public boolean isFinded(int[] pckg) {
                boolean returnStatus = false;

                if (pckg != null) {
                    if (pckg.length > 3) {
                        for (int i = 0; i < pckg.length - 3 && !returnStatus; i++) {
                            if ((pckg[i] == 'd'
                                    && (pckg[i + 1] == 'X' || (char) pckg[i + 1] == 'Y')
                                    && pckg[i + 3] == '='
                                    && Character.isDigit(pckg[i + 2]))
                                    || 
                                    (pckg[i] == 'S' 
                                    && pckg[i + 1] == 't'
                                    && pckg[i + 2] == 'a'
                                    && pckg[i + 3] == 'r')) {
                                returnStatus = true;
                            }
                        }
                    }
                }
                if (!returnStatus) {
                    System.out.println("Mouse falied input buf:");
                    System.out.println(Arrays.toString(pckg));
                    String buf = "";
                    for (int i = 0; i < pckg.length; i++) {
                        buf += (char) pckg[i];
                    }
                    System.out.println("Buf: " + buf);
                }

                return returnStatus;
            }

            @Override
            public int[] getSendPckg() {
                return null;
            }
        }), baudrate);
    }

    public MouseSensorHost(String name, int baudrate) throws SerialPortException {

        serialPort = new SerialPort(name);
        serialPort.openPort();
        serialPort.setParams(baudrate, 8, 1, 0, true, false);
        serialPort.addEventListener(new SerialPortEventListener() {
            @Override
            public void serialEvent(SerialPortEvent serialPortEvent) {
                try {
                    partMessage = serialPort.readString();
                    if (partMessage != null) {
                        inputBuffer += partMessage;
                        while ((movePosition = inputBuffer.indexOf(0x0d)) != -1
                                && inputBuffer.charAt(inputBuffer.length() - 1) != 0x0d) {
                            currentMessage = inputBuffer.substring(0, movePosition + 2);
                            //System.out.println("curmsg: "+currentMessage);
                            sumPosition += movePosition;

                            charIndx = 0;
                            while (currentMessage.charAt(charIndx) == 'd') {
                                charIndx++;
                                if (currentMessage.charAt(charIndx) == 'X') {
                                    toX = true;
                                } else {
                                    toX = false;
                                }
                                charIndx++;
                                elementIndx = currentMessage.charAt(charIndx) - '1';
                                charIndx += 2;
                                while (currentMessage.charAt(charIndx) != 0x09
                                        && currentMessage.charAt(charIndx) != 0x0d) {
                                    //System.out.println("curchar:"+currentMessage.charAt(charIndx)+" int "+(int)currentMessage.charAt(charIndx)+" indx: "+charIndx);
                                    value += currentMessage.charAt(charIndx);
                                    //System.out.println("val:"+value);
                                    charIndx++;
                                }
                                if (toX) {
                                    try {
                                        setDx(elementIndx, Integer.valueOf(value));
                                    } catch (NumberFormatException ex) {
                                        System.out.println("Number exception in MouseSensorHost");
                                    }
                                } else {
                                    try {
                                        setDy(elementIndx, Integer.valueOf(value));
                                    } catch (NumberFormatException ex) {
                                        System.out.println("Number exception in MouseSensorHost");
                                    }
                                }
                                value = "";
                                charIndx++;
                            }
                            translateToListeners(dx[0], dy[0], dx[1], dy[1],
                                    dx[2], dy[2]);
                            for (int i = 0; i < 3; i++) {
                                incX(i, dx[i]);
                                incY(i, dy[i]);
                            }
                            //System.out.println(""+x[2] +" " + y[2]);
                            inputBuffer = inputBuffer.substring(sumPosition + 2);
                            sumPosition = 0;
                        }
                    }
                } catch (SerialPortException ex) {
                    Logger.getLogger(MouseSensorHost.class.getName()).
                            log(Level.SEVERE, null, ex);
                }
            }
        });
    }

    public void closePort() throws SerialPortException {
        serialPort.closePort();
    }

    private synchronized void translateToListeners(int dx1, int dy1, int dx2,
            int dy2, int dx3, int dy3) {
        for (int i = 0; i < listeners.size(); i++) {
            listeners.get(i).measured(dx1, dy1, dx2, dy2, dx3, dy3);
        }
    }

    public synchronized void addMouseSensorListener(MouseSensorListener listener) {
        listeners.add(listener);
    }

    public synchronized void removeMouseSensorListener(
            MouseSensorListener listener) {
        listeners.remove(listener);
    }

    public synchronized void removeAllMouseSensorListener() {
        listeners.clear();
    }

    private synchronized void setDx(int n, int val) {
        this.dx[n] = val;
    }

    private synchronized void setDy(int n, int val) {
        this.dy[n] = val;
    }

    public synchronized int getDx(int n) {
        return dx[n];
    }

    public synchronized int getDy(int n) {
        return dy[n];
    }

    public synchronized int getX(int n) {
        return x[n];
    }

    public synchronized int getY(int n) {
        return y[n];
    }

    private synchronized void incX(int n, int val) {
        this.x[n] += val;
    }

    private synchronized void incY(int n, int val) {
        this.y[n] += val;
    }
}
